/**
 * 创建与怪物的战斗
 * @param {*} characters_id 角色id 
 * @param {*} monster_id 怪物编号/活动编号
 * @param {*} fight_type 战斗类型(结算编号) 
 */
export async function create_monster_fight(characters_id, monster_id, fight_type) {
    let characters = _CharactersData.get(characters_id);
    let character_client_id = G.Characters.get_characters_client_id(characters_id);
    if (characters["战斗开关"] !== 0 && _FightDataCache.has(characters["战斗开关"])) {
        //正在战斗中,无法开启新的战斗
        if (character_client_id !== undefined) {
            ClientUtils.send_basic_prompt(character_client_id, "#R当前处于战斗中,无法加入新的战斗!");
        }
        return;
    }
    // 校验队员是否在战斗
    if (characters["队伍"] !== 0 && _TeamDataCache.has(characters["队伍"])) {
        G.TeamUtils.team_member_callback(characters_id, (index, team_characters_id, args) => {
            let team_characters = _CharactersData.get(team_characters_id);
            if (team_characters["战斗开关"] !== 0 && _FightDataCache.has(team_characters["战斗开关"])) {
                if (args[0] !== undefined) {
                    ClientUtils.send_basic_prompt(character_client_id, `队员#G${team_characters["名称"]}正在战斗中`);
                }
                return;
            }
        }, character_client_id);
    }

    //怪物数据
    let monster_data;
    //校验怪物数据
    let monster_fun = G.Monster.default[monster_id];
    if (monster_fun) {
        monster_data = monster_fun(characters_id);
    } else {
        monster_data = G.Monster.build_activity_monster(characters_id, monster_id);
        if (monster_data === undefined) {
            console.warn(`未定义怪物数据,编号[${monster_id}]`);
            return;
        }
    }
    //初始化战斗数据
    let fight_data = {
        "id": characters_id,
        "战斗状态": "INIT",
        "队伍数据": [],
        "战斗类型": fight_type,
        "战斗发言": [],
        "全局属性": [],
        "全局状态": [],
        "单挑模式": false,
        "PK战斗": false,
        "紧急任务": false,
        "统计数据": {},
        "战斗流程": [],
        "编号下标": new Map(),
    }

    //构建参战单位数据
    build_monster_team_data(fight_data, characters, monster_data);

    _FightDataCache.set(characters_id, fight_data);

    // 使用状态机触发战斗
    init_fight(characters_id);
}

/**
 * 初始化战斗
 * @param {*} fight_id 
 */
function init_fight(fight_id) {
    console.debug(`[${fight_id}] 初始化战斗`)
    let fight_data = _FightDataCache.get(fight_id);
    fight_data["开始时间"] = Math.floor(Date.now() / 1000);
    fight_data["战斗状态"] = "初始化";
    fight_data["回合"] = 0;
    fight_data["需要就绪数量"] = 0;
    fight_data["就绪单位"] = new Set();
    fight_data["指令"] = new Map();
    //计算参战单位信息
    G.FightUtils.computing_fight_unit_data(fight_data);
    //通知客户端加入战斗
    G.FightUtils.notice_client_join_fight(fight_data);
    //进入等待加载完成状态
    fight_data["战斗状态"] = "等待加载完成";
    //进入准备回合的时间
    fight_data["初始化完成时间"] = Math.floor(Date.now() / 1000);
    G.EventCallback.publish_event("战斗开始", fight_data);
    // 加入校验列表
    _CheckFightList.add(fight_data["id"]);
    console.debug(`[${fight_id}] 初始化战斗完成`)
}

/**
 * 设置参战玩家为就绪状态
 * @param {*} characters 
 */
export function set_ready(characters) {
    let fight_data = _FightDataCache.get(characters["战斗开关"]);
    if (fight_data !== undefined) {
        fight_data["就绪单位"].add(characters["id"]);
    }
    // 校验是否全部准备完毕
    check_ready(fight_data);
}

/**
 * 等待所有参战单位准备完成
 * @param {*} fight_data 
 * @returns 
 */
function check_ready(fight_data) {
    console.debug(`[${fight_data["id"]}] 需要完成加载客户端数量:${fight_data["需要就绪数量"]}`);
    console.debug(`[${fight_data["id"]}] 已完成加载客户端数量${fight_data["就绪单位"].size}`);
    fight_data["战斗状态"] = "校验中";
    //如果全部准备完成则通知所有人员进入命令输入回合
    if (fight_data["就绪单位"].size === fight_data["需要就绪数量"]) {
        console.debug(`[${fight_data["id"]}] 所有客户端完成战斗加载,进入等待命令回合`);
        // 从校验列表删除
        _CheckFightList.delete(fight_data["id"]);
        set_waiting_cmd(fight_data);
    } else {
        fight_data["战斗状态"] = "等待加载完成";
    }
}

/**
 * 进入等待命令回合
 * @param {*} fight_data 
 */
export function set_waiting_cmd(fight_data) {
    //通知参战单位进入输入指令回合,发送可用指令信息
    fight_data["战斗状态"] = "发送指令";
    //清空已就绪人员
    fight_data["就绪单位"].clear();
    fight_data["下发指令数量"] = 0;
    G.FightUtils.send_cmd_data(fight_data);
    //进入等待命令
    fight_data["等待指令时间"] = Math.floor(Date.now() / 1000);
    fight_data["战斗状态"] = "等待指令";
    fight_data["回合"] += 1;
    // 加入校验列表
    _CheckFightList.add(fight_data["id"]);
    // 校验命令是否提交完毕
    check_waiting_cmd(fight_data);
}

/**
 * 设置战斗命令 {"1":{"附加":4,"目标":7,"类型":"攻击","id":"36","敌我":0,"参数":""},"mb":[2]}
 * @param {*} characters 
 * @param {*} message_json 
 */
export function set_cmd(characters, message_json) {
    let fight_data = _FightDataCache.get(characters["战斗开关"]);
    //防止刷命令
    if (fight_data && fight_data["战斗状态"] === "等待指令"
        && !fight_data["就绪单位"].has(characters["id"])
        && fight_data["enable_cmd_master_unit"].has(characters["id"])) {
        let master_fight_unit = get_fight_unit_by_characters(fight_data, characters);
        // 存一份历史指令
        characters["历史指令"] = message_json;
        // 主参战单位可用的所有指令
        let enable_cmd = master_fight_unit["enable_cmd"];
        // 为每个操作目标设置指令
        for (let index = 0; index < message_json["mb"].length; index++) {
            // 单位的编号
            let fight_unit_number = message_json["mb"][index];
            // 校验是否可以为目标单位设置指令 
            if (enable_cmd["mb"].includes(fight_unit_number)) {
                let cmd = message_json[index + 1 + ""];
                let fight_unit = get_fight_unit_by_number(fight_data, fight_unit_number);
                fight_unit["指令"] = cmd;
                // 保存自动指令
                fight_unit["自动指令"] = cmd;
                if (fight_unit["类型"] === "角色") {
                    let mb_characters = _CharactersData.get(fight_unit["id"]);
                    mb_characters["自动指令"] = cmd;
                }
                if (fight_unit["认证码"]) {
                    let marster_number = fight_unit["主人编号"];
                    let marster_unit = get_fight_unit_by_number(fight_data, marster_number);
                    let marster_characters = _CharactersData.get(marster_unit["id"]);
                    let pet_data = G.Characters.get_characters_fight_pet_data(marster_characters);
                    pet_data["自动指令"] = cmd;
                }
            }
        }
        // 设置命令已提交
        fight_data["就绪单位"].add(characters["id"]);
        // 校验命令是否提交完毕
        check_waiting_cmd(fight_data);
    }
}

/**
 * 校验命令是否提交完毕
 * @param {*} fight_data 
 */
function check_waiting_cmd(fight_data) {
    console.debug(`[${fight_data["id"]}] 需要提交命令的客户端数量:${fight_data["下发指令数量"]}`);
    console.debug(`[${fight_data["id"]}] 已提交命令的客户端数量${fight_data["就绪单位"].size}`);
    fight_data["战斗状态"] = "校验中";
    if (fight_data["就绪单位"].size === fight_data["下发指令数量"]) {
        // 从校验列表删除
        _CheckFightList.delete(fight_data["id"]);
        console.debug(`[${fight_data["id"]}] 客户端命令已提交完, 开始计算战斗`);
        fight_data["进入播放等待"] = Math.floor(Date.now() / 1000);
        fight_data["播放等待"] = 2;
        // 计算本回合战斗 通知参战人员需要播放的战斗过程
        G.FightUtils.computing_fight_process(fight_data);
        //进入等待播放完成回合
        set_waiting_play_process(fight_data);
    } else {
        fight_data["战斗状态"] = "等待指令";
    }
}

/**
 * 进入等待播放战斗完成回合
 * @param {*} fight_data 
 */
export function set_waiting_play_process(fight_data) {
    fight_data["播放等待"] += Math.floor(Date.now() / 1000);
    console.debug(`[${fight_data["id"]}] 等待战斗单位完成流程播放,预计用时${fight_data["播放等待"] - Math.floor(Date.now() / 1000)}秒 `);
    fight_data["战斗状态"] = "等待播放完成";
    fight_data["就绪单位"].clear();
    fight_data["指令"].clear();
    // 加入校验列表
    _CheckFightList.add(fight_data["id"]);
}

export function add_waiting_play_time(fight_data, time, remark) {
    fight_data["播放等待"] += time;
    console.debug(`增加播放用时 ${time} , ${remark}`);
}

/**
 * 设置战斗单位播放流程完成
 * @param {*} characters 
 */
export function set_play_success(characters) {
    let fight_data = _FightDataCache.get(characters["战斗开关"]);
    console.debug(`[${fight_data["id"]}] 等待战斗单位完成流程播放`);
    //防止重复刷
    if (fight_data !== undefined && fight_data["战斗状态"] === "等待播放完成") {
        fight_data["就绪单位"].add(characters["id"]);
        // 校验是否全部播放完成
        check_waiting_play_fight_process(fight_data);
    }
}

/**
 * 等待战斗过程播放完成
 * @param {*} fight_data 
 * @returns 
 */
function check_waiting_play_fight_process(fight_data) {
    console.debug(`[${fight_data["id"]}] 需要播放完成的数量:${fight_data["需要就绪数量"]}`);
    console.debug(`[${fight_data["id"]}] 已播放完成的数量: ${fight_data["就绪单位"].size}`)
    fight_data["战斗状态"] = "校验中";
    //如果全部准备完成则通知所有人员进入命令输入回合
    if (fight_data["就绪单位"].size === fight_data["需要就绪数量"]) {
        console.debug(`[${fight_data["id"]}] 所有客户端播放战斗流程完成,总用时: ${Math.floor(Date.now() / 1000) - fight_data["进入播放等待"]}秒`);
        // 从校验列表删除
        _CheckFightList.delete(fight_data["id"]);
        check_fight_close(fight_data);
    } else {
        fight_data["战斗状态"] = "等待播放完成";
    }
}

/**
 * 校验是否可以结束战斗
 * @param {*} fight_data 
 */
export function check_fight_close(fight_data) {
    fight_data["战斗状态"] = "校验中";
    G.FightUtils.send_close_fight_process_data(fight_data);
    // 是否可以结束战斗
    let win_team_index = G.FightUtils.is_complete(fight_data);
    if (win_team_index !== undefined) {
        fight_data["结算"] = true;
        fight_data["胜利队伍"] = win_team_index;
        close_fight(fight_data);
    } else {
        set_waiting_cmd(fight_data);
    }
}

/**
 * 结束战斗
 */
export function close_fight(fight_data) {
    console.debug(`[${fight_data["id"]}] 结束战斗`);
    fight_data["战斗状态"] = "结束中";
    // 从校验列表删除
    _CheckFightList.delete(fight_data["id"]);
    if (fight_data !== undefined) {
        // 通知所有队伍结束战斗
        sned_close_data(fight_data);
    }
    if (fight_data !== undefined) {
        fight_data["战斗状态"] = "已结束";
        G.EventCallback.publish_event("结束战斗", fight_data);
    }
    return;
}

/**
 * 退出战斗
 * @param {*} fight_id 
 */
export function exit_fight(fight_id) {
    console.debug(`[${fight_id}] 客户端强制退出战斗`);
    //通知结束战斗
    let fight_data = _FightDataCache.get(fight_id);
    fight_data["结算"] = false;
    close_fight(fight_data)
}

/**
 * 发送结束战斗通知
 * @param {*} fight_data 
 */
export function sned_close_data(fight_data) {
    // 向双方队伍发送结束战斗通知
    fight_data["队伍数据"].forEach(team => {
        //遍历双方队伍
        team.forEach(fight_unit => {
            //非玩家不需要通知
            if (fight_unit["类型"] === "角色") {
                let characters = _CharactersData.get(fight_unit["id"]);
                if (characters) {
                    characters["战斗开关"] = 0;
                    G.MapUtils.update_fight_icon(characters, false);
                    //通知客户端结束战斗
                    ClientUtils.send_characters_client_message(fight_unit["id"], 5505, 1);
                    ClientUtils.send_characters_basic_prompt(fight_unit["id"], "#G已结束战斗");
                }
            }
        });
    });
}


/**
 * 向参战队伍内添加角色数据
 * @param {*} fight_data 
 * @param {*} characters 
 */
function add_characters(unit_number_start, fight_data, characters) {
    fight_data["全局属性"][characters["队伍"]] = {};
    fight_data["统计数据"][characters["队伍"]] = {};
    if (characters["队伍"] !== 0) {
        let team_member_list = [];
        let team_data = G.TeamUtils.get_team_data(characters["队伍"]);
        for (let index = 0; index < team_data["成员"].length; index++) {
            let team_characters = _CharactersData.get(team_data["成员"][index]);
            let data = Object.assign({}, G.Characters.computing_characters_data(team_characters));
            unit_number_start += 1;
            data["编号"] = unit_number_start;
            data["类型"] = "角色";
            data["位置"] = index + 1;
            data["下标"] = team_member_list.length;
            data["队伍下标"] = 0;
            data["武器"] = data["装备"][2];
            fight_data["编号下标"].set(data["编号"], [0, team_member_list.length]);
            data["附加阵法"] = team_data["阵型"];
            if (data["变身数据"]) {
                data["模型"] = data["变身数据"];
            }
            G.FightUnitUtils.init_uint_data(data);
            team_member_list.push(data);
            if (data["参战宝宝"] !== undefined) {
                let pet_data = Object.assign({}, G.Characters.get_characters_fight_pet_data(team_characters));
                pet_data["id"] = data["id"];
                pet_data["主人编号"] = unit_number_start;
                unit_number_start += 1;
                pet_data["编号"] = unit_number_start;
                pet_data["位置"] = data["位置"] + 5;
                pet_data["下标"] = team_member_list.length;
                pet_data["队伍下标"] = 0;
                fight_data["编号下标"].set(pet_data["编号"], [0, team_member_list.length]);
                pet_data["类型"] = "bb";
                pet_data["附加阵法"] = team_data["阵型"];
                pet_data["队伍"] = characters["id"];
                pet_data["自动战斗"] = data["自动战斗"];
                G.FightUnitUtils.init_uint_data(pet_data);
                team_member_list.push(pet_data);
            }
        }
        fight_data["队伍数据"].push(team_member_list);
    } else {
        let team_member_list = [];
        let data = Object.assign({}, G.Characters.computing_characters_data(characters));
        unit_number_start += 1;
        data["编号"] = unit_number_start;
        data["类型"] = "角色";
        data["位置"] = 1;
        data["下标"] = 0;
        data["队伍下标"] = 0;
        data["武器"] = data["装备"][2];
        fight_data["编号下标"].set(data["编号"], [0, team_member_list.length]);
        data["队伍"] = characters["id"];
        data["附加阵法"] = "普通";
        if (data["变身数据"]) {
            data["模型"] = data["变身数据"];
        }
        G.FightUnitUtils.init_uint_data(data);
        team_member_list.push(data);
        if (data["参战宝宝"] !== undefined) {
            let pet_data = Object.assign({}, G.Characters.get_characters_fight_pet_data(characters));
            pet_data["id"] = data["id"];
            pet_data["主人编号"] = unit_number_start;
            unit_number_start += 1;
            pet_data["编号"] = unit_number_start;
            pet_data["位置"] = 6;
            pet_data["下标"] = 1;
            pet_data["队伍下标"] = 0;
            fight_data["编号下标"].set(pet_data["编号"], [0, team_member_list.length]);
            pet_data["类型"] = "bb";
            pet_data["附加阵法"] = "普通";
            pet_data["队伍"] = characters["id"];
            pet_data["自动战斗"] = data["自动战斗"];
            G.FightUnitUtils.init_uint_data(pet_data);
            team_member_list.push(pet_data);
        }
        fight_data["队伍数据"].push(team_member_list);
    }
}

/**
 * 向参战队伍内添加怪物数据
 * @param {*} fight_data 
 * @param {*} monster_data 
 */
function add_monster(unit_number_start, fight_data, monster_data) {
    fight_data["全局属性"][0] = {};
    let team_monster_list = [];
    for (let index = 0; index < monster_data.length; index++) {
        let monster = monster_data[index];
        unit_number_start++;
        monster["编号"] = unit_number_start;
        monster["位置"] = index + 1;
        monster["类型"] = "怪物";
        monster["队伍下标"] = 1;
        monster["下标"] = index;
        fight_data["编号下标"].set(monster["编号"], [1, index]);
        monster["队伍"] = 0;
        monster["附加阵法"] = "普通";
        monster["法术状态"] = {};
        G.FightUnitUtils.init_uint_data(monster);
        team_monster_list.push(monster);
        if (monster["开场发言"]) {
            fight_data["战斗发言"].push({ "id": monster["编号"], "内容": monster["开场发言"] });
        }
    }
    fight_data["队伍数据"].push(team_monster_list);
}

/**
 * 构建参战单位数据
 * @param {*} fight_data 发起战斗的角色信息
 * @param {*} monster_data 怪物对象集合
 * @param {*} characters 
 */
export function build_monster_team_data(fight_data, characters, monster_data) {
    // 战斗单位的编号关联数据 [0] 队伍下标 [1] 队伍内的下标
    add_characters(0, fight_data, characters);
    add_monster(fight_data["队伍数据"][0].length, fight_data, monster_data);
}

/**
 * 所有战斗单位信息
 * @param {*} fight_data 
 * @returns 
 */
export function get_all_fight_unit(fight_data) {
    let all_fight_unit = [];
    fight_data["队伍数据"].forEach((team => {
        team.forEach(fight_unit => {
            all_fight_unit.push(fight_unit);
        });
    }));
    return all_fight_unit;
}

/**
 * 构建客户端需要的战斗数据
 * @param {*} fight_data 
 * @returns 
 */
export function build_client_fight_data(fight_data) {
    let all_fight_unit = get_all_fight_unit(fight_data);
    return [all_fight_unit, {
        "id": fight_data["id"],
        "音乐": 5,
        "单挑模式": fight_data["单挑模式"],
        "PK战斗": fight_data["PK战斗"],
        "紧急任务": fight_data["紧急任务"],
        "总数": all_fight_unit.length,
    }];
}

/**
 * 通知所有参战单位进入战斗，并发送参战单位信息
 * @param {*} fight_data 
 */
export function notice_client_join_fight(fight_data) {
    console.debug(`[${fight_data["id"]}] 开始通知客户端加入战斗`);
    let client_fight_data = build_client_fight_data(fight_data);

    //所有战斗单位的信息
    let all_fight_unit = client_fight_data[0];

    // 下发给客户端的战斗数据
    let send_data = client_fight_data[1];

    //通知双方队伍进入战斗
    fight_data["队伍数据"].forEach(team => {
        //遍历双方队伍
        team.forEach(fight_unit => {
            //非玩家不需要通知
            if (fight_unit["类型"] === "角色") {
                let characters = _CharactersData.get(fight_unit["id"]);
                if (characters !== undefined) {
                    characters["战斗开关"] = fight_data["id"];
                    G.MapUtils.update_fight_icon(characters, true);
                }
                let character_client_id = G.Characters.get_characters_client_id(fight_unit["id"]);
                if (character_client_id !== undefined) {
                    //累计需要等待准备的参战单位
                    fight_data["需要就绪数量"] += 1;
                    send_join_fight_data(character_client_id, all_fight_unit, send_data);
                }
            }
        });
    });
    console.debug(`[${fight_data["id"]}] 通知客户端加入战斗完成`);
}

/**
 * 发送加入战斗和加载战斗单位的数据
 * @param {*} character_client_id 
 * @param {*} send_data 
 * @param {*} all_fight_unit 
 */
export function send_join_fight_data(character_client_id, all_fight_unit, send_data) {
    //通知转入战斗场景
    ClientUtils.send_client_message(character_client_id, 5501, send_data);
    //发送所有战斗单位的信息
    ClientUtils.send_client_message(character_client_id, 5515, all_fight_unit);
}


/**
 * 通知参战单位进入输入指令回合,发送可用指令信息
 * @param {*} fight_data 
 */
export function send_cmd_data(fight_data) {
    console.debug(`${fight_data["id"]} 发送战斗指令开始 `)
    fight_data["enable_cmd_unit"] = new Set();
    fight_data["enable_cmd_master_unit"] = new Set();
    //所有主角色
    let master_characters_list = [];
    // 主角色的编号
    let master_characters_number = new Map();
    // 角色召唤兽的编号
    let characters_pet = new Map();
    //主角色下的助战
    let master_help_fight = new Map();
    //每个角色的主动技能
    let characters_skill = new Map();
    //召唤兽的主动技能
    let pet_skill = new Map();
    // 每个角色的自动指令
    let characters_auto_cmd = new Map();
    // 召唤兽自动指令
    let pet_auto_cmd = new Map();
    // 统计队伍可操作单位信息
    fight_data["队伍数据"].forEach(team => {
        //遍历双方队伍 
        for (let index = 0; index < team.length; index++) {
            let fight_unit = team[index];
            //只统计非自动战斗的角色单位
            if (fight_unit["类型"] === "角色" && !fight_unit["自动战斗"]) {
                // 是否
                let character_client_id = G.Characters.get_characters_client_id(fight_unit["id"]);
                characters_skill.set(fight_unit["id"], fight_unit["主动技能"]);
                characters_auto_cmd.set(fight_unit["id"], fight_unit["自动指令"]);
                if (character_client_id !== undefined) {
                    //主登录角色 
                    master_characters_list.push(fight_unit);
                    master_characters_number.set(fight_unit["id"], fight_unit["编号"]);
                    master_help_fight.set(fight_unit["id"], [])
                } else {
                    //没有客户端id要么离线要么是助战角色
                    let master_id = G.Characters.get_master_characters_id(fight_unit["id"]);
                    if (master_id !== undefined) {
                        //助战角色
                        let help_fight_list = master_help_fight.get(master_id);
                        help_fight_list.push(fight_unit);
                    } else {
                        // TODO 掉线了
                    }
                }
                // 召唤兽
                if (fight_unit["参战宝宝"]) {
                    let pet_data = team[index + 1];
                    characters_pet.set(fight_unit["id"], pet_data);
                    pet_skill.set(fight_unit["id"], pet_data["主动技能"]);
                    pet_auto_cmd.set(fight_unit["id"], pet_data["自动指令"])
                }
            }
        }
    });
    //向主登录角色发送可操作指令信息
    for (let index = 0; index < master_characters_list.length; index++) {
        // 累加需要准备的客户端数量
        fight_data["下发指令数量"] += 1;
        let master_characters = master_characters_list[index];
        let master_characters_id = master_characters["id"];
        // 发送战斗发言
        for (let j = 0; j < fight_data["战斗发言"].length; j++) {
            let fight_chat = fight_data["战斗发言"][j];
            ClientUtils.send_characters_client_message(master_characters_id, 5512, { "id": fight_chat["id"], "文本": fight_chat["内容"] });
        }
        let mb_list = [];
        let id_list = [];
        let skill_list = [];
        let auto_cmd_list = [];
        //主角色
        if (G.FightUnitUtils.get_unit_status(master_characters)) {
            id_list.push(master_characters_id);
            mb_list.push(master_characters_number.get(master_characters_id));
            skill_list.push(characters_skill.get(master_characters_id));
            auto_cmd_list.push(characters_auto_cmd.get(master_characters_id));
        }
        //主角色召唤兽参战
        if (characters_pet.has(master_characters_id)) {
            let pet_data = characters_pet.get(master_characters_id);
            if (G.FightUnitUtils.get_unit_status(pet_data)) {
                id_list.push(master_characters_id);
                mb_list.push(pet_data["编号"]);
                skill_list.push(pet_skill.get(master_characters_id));
                auto_cmd_list.push(pet_auto_cmd.get(master_characters_id));
            }
        }
        //助战列表
        if (master_help_fight.has(master_characters_id)) {
            let help_fight_list = master_help_fight.get(master_characters_id);
            for (let index = 0; index < help_fight_list.length; index++) {
                let help_fight = help_fight_list[index];
                let help_fight_id = help_fight["id"];
                //助战
                if (G.FightUnitUtils.get_unit_status(help_fight)) {
                    id_list.push(help_fight_id);
                    mb_list.push(help_fight["编号"]);
                    skill_list.push(characters_skill.get(help_fight_id));
                    auto_cmd_list.push(characters_auto_cmd.get(master_characters_id));
                }
                //助战召唤兽参战
                let pet_data = characters_pet.get(help_fight_id);
                if (characters_pet.has(help_fight_id) && G.FightUnitUtils.get_unit_status(pet_data)) {
                    id_list.push(help_fight_id);
                    mb_list.push(pet_data["编号"]);
                    skill_list.push(pet_skill.get(help_fight_id));
                    auto_cmd_list.push(pet_auto_cmd.get(help_fight_id));
                }
            }
        }
        // 发送指令信息
        let send_data = {
            //可以操作的目标编号 
            "mb": mb_list,
            //可以操作的目标id
            "id": id_list,
            //主动技能
            "zdjn": skill_list,
            //自动指令 
            "zdzl": auto_cmd_list,
        }
        master_characters["enable_cmd"] = send_data;
        fight_data["enable_cmd_master_unit"].add(master_characters_id);
        ClientUtils.send_characters_client_message(master_characters_id, 5503, send_data);
    }
    fight_data["战斗发言"] = [];
    console.debug(`${fight_data["id"]} 发送战斗指令完成 `)
}

/**
 * 回合开始前的处理
 * @param {*} fight_data 
 */
function fight_befor_computing(fight_data) {
    console.debug(`回合开始前的处理`)
    fight_data["队伍数据"].forEach((team => {
        team.forEach(fight_unit => {
            console.debug(`回合开始前的处理开始 编号 ${fight_unit["编号"]} 气血 ${fight_unit["气血"]}`)

            //召唤兽特性洞察
            if (fight_unit["认证码"] && fight_unit["洞察"] && G.RandomUtils.chance(fight_unit["洞察"])) {
                let survive_unit = get_enemy_team_single_survive_unit(fight_data, fight_unit);
                let key = G.RandomUtils.random_get_array(["气血", "魔法"]);
                let characters_id = fight_unit["认证码"].split("_")[0];
                ClientUtils.send_characters_basic_prompt(characters_id, `#Y/你的召唤兽发现#G/${survive_unit["名称"]}#Y/当前#G/${key}#Y/剩余#G/${survive_unit[key]}点`);
            }

            // 批量执行法术状态的回合开始前算法
            for (const key in fight_unit["法术状态"]) {
                let skill_data = G.SkillData.default[key];
                if (skill_data && skill_data["回合开始前"]) {
                    skill_data["回合开始前"](fight_data, fight_unit);
                }
            }

            // 批量执行经脉回合开始前算法
            if (fight_unit["奇经八脉"] && fight_unit["门派"] !== "无门派") {
                let sects_jing_mai_data = G.JingMaiData.default[fight_unit["门派"]];
                // 门派
                if (sects_jing_mai_data["回合开始前"]) {
                    sects_jing_mai_data["回合开始前"](fight_data, fight_unit);
                }
                // "当前流派"
                if (sects_jing_mai_data[fight_unit["奇经八脉"]["当前流派"]]["回合开始前"]) {
                    sects_jing_mai_data[fight_unit["奇经八脉"]["当前流派"]]["回合开始前"](fight_data, fight_unit);
                }
                // 已点经脉
                for (const key in fight_unit["奇经八脉"]) {
                    if (fight_unit["奇经八脉"][key] && fight_unit["奇经八脉"][key] === 1 && sects_jing_mai_data[key]["回合开始前"]) {
                        sects_jing_mai_data[key]["回合开始前"](fight_data, fight_unit);
                    }
                }
            }
            console.debug(`回合开始前的处理结束 编号 ${fight_unit["编号"]} 气血 ${fight_unit["气血"]}`)
        });
    }));
}

/**
 * 回合结束后的处理
 * @param {*} fight_data 
 */
function fight_after_computing(fight_data) {
    //回合结束后清理过期全局状态 TODO 加载法宝信息时初始化
    for (let status_key in fight_data["全局状态"]) {
        let global_status = fight_data["全局状态"][status_key];
        if (global_status["回合"] === 0) {
            fight_data["全局状态"][status_key] = undefined;
        }
    }
    // 回合结束后对每个单位的处理
    fight_data["队伍数据"].forEach((team => {
        team.forEach(fight_unit => {
            // 处理技能冷却
            for (let index = 0; index < fight_unit["主动技能"].length; index++) {
                const skill = fight_unit["主动技能"][index];
                if (skill["剩余冷却回合"]) {
                    skill["剩余冷却回合"] -= 1;
                    if (skill["剩余冷却回合"] < 1) {
                        skill["剩余冷却回合"] = undefined;
                    }
                }
            }
            // 同步法术状态
            G.FightStatusUtils.sync_unit_status(fight_data, fight_unit);
        });
    }));
}


/**
 * 计算参战队伍的执行顺序
 * 
 * team_order[0] 先执行队伍下标
 * 
 * team_order[0][1] 先执行队伍的队员下标排序集合
 * 
 * team_order[1] 后执行队伍下标 
 * 
 * team_order[1][1] 后执行队伍的队员下标排序集合
 * 
 * @param {*} fight_data 
 * @returns team_order 
 */
function computing_fight_order(fight_data) {
    // 计算双方队伍总速度 teamSpeeds[0] 队伍1的速度 teamSpeeds[1] 队伍2的速度
    let teamSpeeds = fight_data["队伍数据"].map(team => {
        return team.reduce((sum, member) => sum + (member["临时速度"] || 0), 0);
    });
    // 对每个队伍内部按速度和位置排序，返回原始索引数组
    let sortedIndexes = fight_data["队伍数据"].map(team => {
        // 创建包含索引的数组
        let indexedTeam = team.map((member, index) => ({ member, index }));
        // 排序
        indexedTeam.sort((a, b) => {
            // 先按速度降序
            if (b.member["临时速度"] !== a.member["临时速度"]) {
                return b.member["临时速度"] - a.member["临时速度"];
            }
            // 速度相同则按位置升序
            return a.member["位置"] - b.member["位置"];
        });
        // 返回排序后的索引数组
        return indexedTeam.map(item => item.index);
    });
    // 3.根据队伍总速度决定行动顺序
    return teamSpeeds[0] > teamSpeeds[1] ? [[0, sortedIndexes[0]], [1, sortedIndexes[1]]] : [[1, sortedIndexes[1]], [0, sortedIndexes[0]]];
}


/**
 * 演算战斗过程
 * @param {*} fight_data 
 */
export function computing_fight_process(fight_data) {
    console.debug(`[${fight_data["id"]}] 开始演算战斗过程`)
    // 回合开始前的处理
    fight_befor_computing(fight_data);
    // 根据速度来决定执行顺序
    let action_order = computing_fight_order(fight_data);
    // 按照速度排序执行队伍指令
    G.FightCmdUtils.execute_fight_cmd(fight_data, action_order);
    // 回合结束后的处理
    fight_after_computing(fight_data);
    //发送战斗流程信息给所有客户端播放
    send_play_fight_process_data(fight_data);
    //清空战斗流程
    fight_data["战斗流程"] = [];
}

/**
 * 发送结束战斗流程数据
 */
export function send_close_fight_process_data(fight_data) {
    //所有战斗单位的信息
    let all_fight_unit = [];
    fight_data["队伍数据"].forEach((team => {
        team.forEach(fight_unit => {
            all_fight_unit.push({
                "编号": fight_unit["编号"],
                "人物状态": {
                    "气血": fight_unit["气血"],
                    "最大气血": fight_unit["最大气血"],
                    "气血上限": fight_unit["气血上限"],
                    "魔法": fight_unit["魔法"],
                    "最大魔法": fight_unit["最大魔法"],
                    "愤怒": fight_unit["愤怒"],
                    "护盾": fight_unit["护盾"],
                    "超级战意": fight_unit["超级战意"],
                    "如意神通": fight_unit["如意神通"],
                    "五行珠": fight_unit["五行珠"],
                    "人参果": fight_unit["人参果"],
                    "骤雨": fight_unit["骤雨"],
                },
                "法术状态": fight_unit["法术状态"],
                "共生": fight_unit["共生"],
                "黎魂": fight_unit["黎魂"],
                "丸子附加": {
                    // TODO 客户端与服务端数据对齐
                    "超级必杀": fight_unit["超级必杀"],
                    "超级夜战": fight_unit["超级夜战"],
                    "超级偷袭": fight_unit["超级偷袭"],
                    "超级敏捷": fight_unit["超级敏捷"],
                }
            });
        });
    }));
    fight_data["队伍数据"].forEach(team => {
        //遍历双方队伍
        team.forEach(fight_unit => {
            //非玩家不需要通知
            if (fight_unit["类型"] === "角色") {
                //发送单位信息
                ClientUtils.send_characters_client_message(fight_unit["id"], 5518, all_fight_unit);
            }
        });
    });
}

/**
 * 发送战斗流程数据
 */
function send_play_fight_process_data(fight_data) {
    let process_data = fight_data["战斗流程"];
    fight_data["队伍数据"].forEach(team => {
        //遍历双方队伍
        team.forEach(fight_unit => {
            //非玩家不需要通知
            if (fight_unit["类型"] === "角色") {
                //发送战斗流程
                ClientUtils.send_characters_client_message(fight_unit["id"], 5504, process_data);
            }
        });
    });
}

/**
 * 计算每个战斗单位的属性
 * @param {*} fight_data 
 */
export function computing_fight_unit_data(fight_data) {
    console.debug(`[${fight_data["id"]}] 开始计算战斗单位属性`);
    fight_data["队伍数据"].forEach(team => {
        //遍历双方队伍
        team.forEach(fight_unit => {
            if (fight_unit["类型"] === "角色") {
                G.FightUnitUtils.computing_characters_fight_unit_data(fight_data, fight_unit);
            } else if (fight_unit["类型"] === "bb") {
                G.FightUnitUtils.computing_pet_unit_data(fight_data, fight_unit);
            } else if (fight_unit["类型"] === "怪物") {
                G.FightUnitUtils.computing_monster_unit_data(fight_data, fight_unit);
            }
        });
    });
    console.debug(`[${fight_data["id"]}] 计算战斗单位属性结束`);
}

/**
 * 战斗是否结束
 * @param {*} fight_data 
 */
export function is_complete(fight_data) {
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        //遍历双方队伍  
        let team = fight_data["队伍数据"][index];
        let die_count = 0;
        for (let j = 0; j < team.length; j++) {
            let fight_unit = team[j];
            if (fight_unit["气血"] <= 0 || fight_unit["捕捉"] || fight_unit["逃跑"]) {
                die_count++;
            }
        }
        console.debug(`是否可以结束战斗 ===> 队伍：${index} 死亡 : ${die_count}  队员: ${team.length}`)
        if (die_count === team.length) {
            return index === 0 ? 1 : 0;
        }
    }
    return undefined;
}

/**
 * 同步角色和召唤兽的数据
 * @param {*} fight_data 
 */
export function sync_characters_and_pet_data(fight_data) {
    console.debug("同步角色和召唤兽的数据");
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        let team = fight_data["队伍数据"][index];
        //遍历己方队伍
        for (let j = 0; j < team.length; j++) {
            let fight_unit = team[j];
            if (fight_unit["类型"] === "角色" || fight_unit["认证码"]) {
                let unit_data;
                let marster_characters
                if (fight_unit["类型"] === "角色") {
                    unit_data = _CharactersData.get(fight_unit["id"]);
                    marster_characters = unit_data;
                }
                if (fight_unit["认证码"]) {
                    let marster_number = fight_unit["主人编号"];
                    let marster_unit = get_fight_unit_by_number(fight_data, marster_number);
                    marster_characters = _CharactersData.get(marster_unit["id"]);
                    unit_data = G.Characters.get_characters_fight_pet_data(marster_characters);
                }
                if (unit_data) {
                    marster_characters["气血"] = Math.max(fight_unit["气血"], 1);
                    marster_characters["魔法"] = fight_unit["魔法"];
                    //同步角色道具效果
                    G.Characters.sync_characters_item_status(marster_characters);
                    if (fight_unit["逃跑"] && fight_unit["认证码"]) {
                        marster_characters["参战宝宝"] = undefined;
                        unit_data["参战信息"] = 0;
                    }
                }
                G.Characters.refrush_characters_data(marster_characters);
            }
        }
    }
}

/**
 * 全部离线
 * @param {*} fight_data 
 */
export function all_offline(fight_data, is_check_play = false) {
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        //遍历双方队伍  
        let team = fight_data["队伍数据"][index];
        let survive_unit = 0;
        for (let j = 0; j < team.length; j++) {
            let fight_unit = team[j];
            if (fight_unit["类型"] === "角色" && _OnlineCharactersData.has(fight_unit["id"])) {
                return false;
            }
        }
        if (survive_unit === 0) {
            return index === 0 ? 1 : 0;
        }
    }
    if (is_check_play) {
        for (let index = 0; index < fight_data["play_list"].length; index++) {
            const play_unit = fight_data["play_list"][index]
            if (_OnlineCharactersData.has(play_unit["id"])) {
                return false;
            }
        }
    }
    return true;
}

/**
 * 校验参战单位是否为指定门派，并且本队伍唯一
 * @param {*} fight_unit 
 */
export function check_fight_unit_sects_is_single(fight_data, fight_unit, sects_name) {
    if (fight_unit["门派"] !== sects_name) {
        return false;
    }
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        let team = fight_data["队伍数据"][index];
        if (team["队伍"] === fight_unit["队伍"]) {
            //遍历己方队伍
            for (let j = 0; j < team.length; j++) {
                let unit = team[j];
                if (unit["id"] !== fight_unit["id"] && unit["门派"] === sects_name) {
                    return false;
                }
            }
        }
    }
    return true;
}

/**
 * 获取队友同门派数量
 * @param {*} fight_unit 
 */
export function get_friend_team_sects_count(fight_data, fight_unit) {
    let count = 0;
    let sects_name = fight_unit["门派"];
    let team_data = fight_data["队伍数据"][fight_unit["队伍下标"]];
    team_data.forEach(unit => {
        if (unit["门派"] === sects_name) {
            sects_name++;
        }
    });
    return count;
}

/**
 * 获取敌方队伍血量最低的单位(排除不可操作的目标)
 * @param {*} fight_data 
 * @param {*} fight_unit 
 * @returns 
 */
export function get_enemy_hp_min_unit(fight_data, fight_unit) {
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        let team = fight_data["队伍数据"][index];
        if (team["队伍"] !== fight_unit["队伍"]) {
            let list = [];
            //遍历敌方队伍并过滤
            for (let j = 0; j < team.length; j++) {
                let unit = team[j];
                if (G.FightUnitUtils.get_target_unit_status(fight_unit, unit, 1)) {
                    list.push(unit);
                }
            }
            // 创建包含索引的数组
            let indexedTeam = list.map((member, index) => ([member, index]));
            // 排序
            indexedTeam.sort((a, b) => {
                return a[0].member["气血"] - b[0].member["气血"];
            });
            return indexedTeam[indexedTeam.length - 1][0];
        }
    }
}

export function spedd_order() {

}

/**
 * 取队伍一速 校验是否为队伍内速度最快的
 * @param {*} fight_data 
 * @param {*} fight_unit 
 * @returns 
 */
export function check_speed_team_no_one(fight_data, fight_unit) {
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        const team = fight_data["队伍数据"][index];
        if (team[0]["队伍"] === fight_unit["队伍"]) {
            for (let j = 0; j < team.length; j++) {
                let unit = team[j];
                if (unit["类型"] === "角色" && unit["编号"] !== fight_unit["编号"] && unit["临时速度"] > fight_unit["临时速度"]) {
                    return false;
                }
            }
        }
    }
    return true;
}

/**
 * 从敌方队伍中查找一个仍然存活并可操作的单位
 */
export function get_enemy_team_single_survive_unit(fight_data, fight_unit) {
    console.debug(`从敌方队伍中查找一个仍然存活并可操作的单位`);
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        let team = fight_data["队伍数据"][index];
        if (team[0]["队伍"] !== fight_unit["队伍"]) {
            // 优先攻击速度最快的
            let order_list = speed_order(team);
            for (let j = 0; j < order_list.length; j++) {
                let element = order_list[j];
                if (G.FightUnitUtils.get_target_unit_status(fight_unit, element, 1)) {
                    return element;
                }
            }
        }
    }
    console.debug(`未找到`);
    return undefined;
}

/**
 * 从敌方队伍中查找多个仍然存活并可操作的单位
 */
export function get_enemy_team_group_survive_unit(fight_data, fight_unit, target_unit, number) {
    console.debug(`从敌方队伍中查找${number}个仍然存活并可行动的单位=> ${fight_unit["编号"]} ${target_unit["编号"]}`);
    let list = [];
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        let team = fight_data["队伍数据"][index];
        if (team[0]["队伍"] !== fight_unit["队伍"]) {
            if (target_unit && G.FightUnitUtils.get_target_unit_status(fight_unit, target_unit, 1)) {
                list.push(target_unit);
            }
            for (let j = 0; j < team.length; j++) {
                let element = team[j];
                if (list.length === number) {
                    break;
                } else if ((target_unit === null || element["编号"] !== target_unit["编号"]) && G.FightUnitUtils.get_target_unit_status(fight_unit, element, 1)) {
                    list.push(element);
                }
            }
        }
    }
    // 优先攻击速度最快的
    return speed_order(list);
}

/**
 * 从敌方队伍中查找所有单位
 */
export function get_enemy_team_group_all_unit(fight_data, fight_unit) {
    console.debug(`从敌方队伍中查找所有单位=> ${fight_unit["编号"]}`);
    let list = [];
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        let team = fight_data["队伍数据"][index];
        if (team[0]["队伍"] !== fight_unit["队伍"]) {
            list = team;
        }
    }
    return list;
}

/**
 * 从敌方队伍中查找所有召唤兽单位
 */
export function get_enemy_team_group_all_pet_unit(fight_data, fight_unit) {
    console.debug(`从敌方队伍中查找所有召唤兽单位=> ${fight_unit["编号"]}`);
    let list = [];
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        let team = fight_data["队伍数据"][index];
        if (team[0]["队伍"] !== fight_unit["队伍"]) {
            for (let j = 0; j < team.length; j++) {
                let element = team[j];
                if (element["类型"] === "bb") {
                    list.push(element);
                }
            }
        }
    }
    return list;
}

/**
 * 从友方队伍中查找一个仍然存活并可操作的单位
 */
export function get_friend_team_single_survive_unit(fight_data, fight_unit) {
    console.debug(`从友方队伍中查找一个仍然存活并可操作的单位`);
    let team_data = fight_data["队伍数据"][fight_unit["队伍下标"]];
    for (let index = 0; index < team_data.length; index++) {
        let element = team_data[index];
        if (element["编号"] !== fight_unit["编号"] && G.FightUnitUtils.get_target_unit_status(fight_unit, element, 1)) {
            return element;
        }
    }
    console.debug(`未找到`);
    return undefined;
}

/**
 * 根据技能类型自动获取一个目标
 * @param {*} fight_data 
 * @param {*} fight_unit
 * @param {*} skill_name 
 */
export function get_target_unit_by_skill_name(fight_data, fight_unit, skill_name) {
    let skill_data = G.SkillData.default[skill_name];
    if (skill_data && (skill_data["技能类型"] === "增益" || skill_data["技能类型"] === "恢复")) {
        if (skill_data["指定对象"] === "自己") {
            console.debug(`根据技能类型自动获取一个目标 => 技能指定自己`);
            fight_unit["指令"]["目标"] = fight_unit["编号"];
        } else {
            console.debug(`根据技能类型自动获取一个目标 => 补充友方目标`);
            let target_unit = get_friend_team_single_survive_unit(fight_data, fight_unit);
            if (target_unit) {
                fight_unit["指令"]["目标"] = target_unit["编号"];
            }
        }
    } else {
        console.debug(`根据技能类型自动获取一个目标 => 补充敌方目标`);
        let target_unit = get_enemy_team_single_survive_unit(fight_data, fight_unit);
        if (target_unit) {
            fight_unit["指令"]["目标"] = target_unit["编号"];
        }
    }
}

/**
 * 气血排序
 * @param {*} member_list 
 * @param {*} number 
 * @returns 
 */
export function hp_order(member_list, number) {
    let data = [];
    let hp_index_list = member_list.map((member, index) => [member["气血"] / member["最大气血"] * 100, index]);
    hp_index_list.sort((a, b) => { return a[0] - b[0] });
    for (let index = 0; index < hp_index_list.length; index++) {
        if (data.length < number) {
            data.push(member_list[hp_index_list[index][1]]);
        }
    }
    return data;
}

/**
 * 速度排序
 * @param {*} member_list 
 * @returns 
 */
function speed_order(member_list) {
    let data = [];
    let speed_index_list = member_list.map((member, index) => [member["临时速度"], index]);
    speed_index_list.sort((a, b) => { return a[0] - b[0] });
    for (let index = 0; index < speed_index_list.length; index++) {
        data.push(member_list[speed_index_list[index][1]]);
    }
    return data;
}


/**
 * 从友方队伍中查找多个仍然存活并可操作的召唤兽单位
 */
export function get_friend_team_group_survive_bb_unit(fight_data, fight_unit, max_number, skill_name) {
    let target_list = [];
    if (G.FightUnitUtils.get_target_unit_status(fight_unit, fight_unit, 1) && fight_unit["认证码"]) {
        target_list.push(fight_unit);
    }
    let list = G.FightUtils.get_friend_team_group_survive_unit(fight_data, fight_unit, 99, skill_name);
    for (let index = 0; index < list.length; index++) {
        if (list.length === max_number) {
            break;
        } else if (list[index]["认证码"] && target_list.length < max_number) {
            target_list.push(list[index]);
        }
    }
    return target_list;
}

/**
 * 从友方队伍中查找多个仍然存活并可操作的角色单位
 */
export function get_friend_team_group_characters_unit(fight_data, fight_unit, max_number) {
    console.debug(`从友方队伍中查找${max_number}个仍然存活并可行动的单位=> ${fight_unit["编号"]}`);
    let list = [];
    if (G.FightUnitUtils.get_target_unit_status(fight_unit, fight_unit, 1) && fight_unit["类型"] === "角色") {
        list.push(fight_unit);
    }
    let team_data = fight_data["队伍数据"][fight_unit["队伍下标"]];
    for (let index = 0; index < team_data.length; index++) {
        let unit = team_data[index];
        if (list.length === max_number) {
            break;
        } else if (unit["编号"] !== fight_unit["编号"] && unit["类型"] === "角色" && G.FightUnitUtils.get_target_unit_status(fight_unit, unit, 1)) {
            list.push(unit);
        }
    }
    return list;
}

/**
 * 查找所有友方队伍单位
 */
export function get_friend_team_all_unit(fight_data, fight_unit) {
    return fight_data["队伍数据"][fight_unit["队伍下标"]];
}

/**
 * 从友方队伍中查找多个仍然存活并可操作的单位
 */
export function get_friend_team_group_survive_unit(fight_data, fight_unit, max_number, skill_name) {
    let team_data = fight_data["队伍数据"][fight_unit["队伍下标"]];
    let member_list = [];
    // 如果没有指定技能则取所有可以被选中的友方单位，包括自己
    if (skill_name === undefined) {
        if (G.FightUnitUtils.get_target_unit_status(fight_unit, fight_unit, 1)) {
            member_list.push(fight_unit);
        }
        for (let index = 0; index < team_data.length; index++) {
            if (member_list.length >= max_number) {
                return member_list;
            }
            let element = team_data[index]
            if (member_list.length < max_number
                && element["编号"] !== fight_unit["编号"]
                && G.FightUnitUtils.get_target_unit_status(fight_unit, element, 1)
            ) {
                member_list.push(element);
            }
        }
        return member_list;
    }
    // 如果指定技能则优先取技能算法的结果
    let skill_data = G.SkillData.default[skill_name];
    if (skill_data && skill_data["取队友"]) {
        console.debug(`技能取队友, 技能 ${skill_name}`)
        return skill_data["取队友"](fight_data, fight_unit, max_number, team_data);
    }
    // 如果技能没有定义算法，则取具有指定法术状态的单位，包括自己
    if (G.FightUnitUtils.get_target_unit_status(fight_unit, fight_unit, 1) && fight_unit["法术状态"][skill_name]) {
        member_list.push(fight_unit);
    }
    for (let index = 0; index < team_data.length; index++) {
        if (member_list.length >= max_number) {
            return member_list;
        }
        let element = team_data[index]
        if (member_list.length < max_number
            && element["编号"] !== fight_unit["编号"]
            && G.FightUnitUtils.get_target_unit_status(fight_unit, element, 1)
            && element["法术状态"][skill_name]) {
            member_list.push(element);
        }
    }
    return member_list;
}


/**
 * 从敌方队伍中查找多个仍然存活并可操作的召唤兽单位
 */
export function get_enemy_team_group_survive_bb_unit(fight_data, fight_unit, target_unit, max_number) {
    console.debug(`从敌方队伍中查找${max_number}个仍然存活并可行动的bb单位=> ${fight_unit["编号"]} ${target_unit["编号"]}`);
    let list = [];
    if (G.FightUnitUtils.get_target_unit_status(fight_unit, target_unit, 1)) {
        list.push(target_unit);
    }
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        let team = fight_data["队伍数据"][index];
        if (team[0]["队伍"] !== fight_unit["队伍"]) {
            for (let j = 0; j < team.length; j++) {
                let element = team[j];
                if (list.length === max_number) {
                    break;
                } else if (element["编号"] !== target_unit["编号"] && element["类型"] === "bb" && G.FightUnitUtils.get_target_unit_status(fight_unit, element, 1)) {
                    list.push(element);
                }
            }
        }
    }
    // 优先攻击速度最快的
    return speed_order(list);
}


/**
 * 从敌方队伍中查找多个仍然存活并可操作的角色单位
 */
export function get_enemy_team_group_characters_unit(fight_data, fight_unit, target_unit, max_number) {
    console.debug(`从敌方队伍中查找${max_number}个仍然存活并可行动的角色单位=> ${fight_unit["编号"]} ${target_unit["编号"]}`);
    let list = [];
    if (G.FightUnitUtils.get_target_unit_status(fight_unit, target_unit, 1)) {
        list.push(target_unit);
    }
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        let team = fight_data["队伍数据"][index];
        if (team[0]["队伍"] !== fight_unit["队伍"]) {
            for (let j = 0; j < team.length; j++) {
                let element = team[j];
                if (list.length === max_number) {
                    break;
                } else if (element["编号"] !== target_unit["编号"] && element["类型"] === "角色" && G.FightUnitUtils.get_target_unit_status(fight_unit, element, 1)) {
                    list.push(element);
                }
            }
        }
    }
    // 优先攻击速度最快的
    return speed_order(list);
}


/**
 * 根据编号获取参战单位
 * @param {*} fight_data 
 * @param {*} fight_unit_number 
 * @returns 
 */
export function get_fight_unit_by_number(fight_data, fight_unit_number) {
    if (fight_data && fight_unit_number) {
        // 操作的战斗单位下标数据
        let number_index_data = fight_data["编号下标"].get(fight_unit_number);
        if (number_index_data) {
            return fight_data["队伍数据"][number_index_data[0]][number_index_data[1]];
        }
    }
    return undefined;
}

/**
 * 根据角色信息获取参战单位
 * @param {*} fight_data 
 * @param {*} characters 
 * @returns 
 */
export function get_fight_unit_by_characters(fight_data, characters) {
    // 操作的战斗单位下标数据
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        //遍历双方队伍  
        let team = fight_data["队伍数据"][index];
        if (team[0]["队伍"] === characters["队伍"] || team[0]["队伍"] === characters["id"]) {
            for (let j = 0; j < team.length; j++) {
                if (team[j]["id"] === characters["id"]) {
                    return team[j];
                }
            }
        }
    }
    return undefined;
}

/**
 * 取五行克制
 * @param {*} src 
 * @param {*} target 
 * @returns 
 */
export function get_wx_suppress(src, target) {
    if (target === "木" && src === "金") {
        return true
    } else if (src === "木" && target === "土") {
        return true
    } else if (src === "土" && target === "水") {
        return true
    } else if (src === "水" && target === "火") {
        return true
    } else if (src === "火" && target === "金") {
        return true
    }
    return false
}

/**
 * 取五行相生
 * @param {*} src 
 * @returns 
 */
export function get_wx_buff(src) {
    if (src === "金") {
        return "水";
    } else if (src === "木") {
        return "水";
    } else if (src === "水") {
        return "木";
    } else if (src === "火") {
        return "土";
    } else if (src === "土") {
        return "金";
    }
}

/**
 * 添加自恋发言
 * @param {*} fight_data 
 * @param {*} fight_unit 
 */
export function add_zilian_chat(fight_data, fight_unit) {
    let characters_id = fight_unit["认证码"].split("_")[0];
    let characters = _CharactersData.get(characters_id);
    let org_pet = characters["召唤兽"][fight_unit["index"]];
    let text = `#G/qqq|${fight_unit["名称"]}*${fight_unit["认证码"]}/[${fight_unit["名称"]}#W#28`;
    let url = {};
    url["1"] = org_pet;
    url["索引类型"] = "召唤兽";
    if (characters["队伍"] === 0) {
        ClientUtils.send_characters_client_message()
        ClientUtils.send_characters_client_message(characters_id, 113, { "内容": text, "频道": "dw", "超链接": url })
    } else {
        G.TeamUtils.send_team_url_message(fight_unit["队伍"], { "内容": text, "频道": "dw", "超链接": url });
    }
    fight_data["队伍数据"].forEach((team => {
        team.forEach(unit => {
            ClientUtils.send_characters_client_message(unit["id"], 5512, { "id": fight_unit["编号"], "队伍": true, "文本": text });
        });
    }));
}

/**
 * 获得敌方指定状态数量 以及总角色单位数
 * @param {*} fight_data 
 * @param {*} status_name 
 */
export function get_enemy_ap_status_count(fight_data, fight_unit, status_name) {
    let all_staus_count = 0;
    let characters_staus_count = 0;
    let pet_staus_count = 0;
    let monster_staus_count = 0;
    let all_unit_count = 0;
    let characters_unit_count = 0;
    let pet_unit_count = 0;
    let monster_unit_count = 0;
    fight_data["队伍数据"].forEach((team => {
        if (team[0]["队伍"] !== fight_unit["队伍"]) {
            team.forEach(unit => {
                all_unit_count++;
                if (unit["法术状态"][status_name]) {
                    all_staus_count++;
                    switch (unit["类型"]) {
                        case "角色":
                            characters_staus_count++;
                            break;
                        case "bb":
                            pet_staus_count++;
                            break;
                        case "怪物":
                            monster_staus_count++;
                            break;
                        default:
                            break;
                    }
                }
                switch (unit["类型"]) {
                    case "角色":
                        characters_unit_count++;
                        break;
                    case "bb":
                        pet_unit_count++;
                        break;
                    case "怪物":
                        monster_unit_count++;
                        break;
                    default:
                        break;
                }
            });
        }
    }));
    return {
        "状态数量": all_staus_count,
        "角色状态数量": characters_staus_count,
        "唤兽状态数量": pet_staus_count,
        "怪物状态数量": monster_staus_count,
        "单位数量": all_unit_count,
        "角色数量": characters_unit_count,
        "召唤兽数量": pet_unit_count,
        "怪物数量": monster_unit_count,
    };
}

/**
 * 获得友方指定状态数量 以及总角色单位数
 * @param {*} fight_data 
 * @param {*} status_name 
 */
export function get_friend_ap_status_count(fight_data, fight_unit, status_name) {
    let status_count = 0;
    let unit_count = 0;
    fight_data["队伍数据"][fight_unit["队伍下标"]].forEach(unit => {
        if (unit["类型"] === "角色") {
            unit_count++;
            if (unit["法术状态"] && unit["法术状态"][status_name]) {
                status_count++;
            }
        }
    });
    return [status_count, unit_count];
}

/**
 * 获得所有角色单位的某项法术状态的总数 以及总角色单位数
 * @param {*} fight_data 
 * @param {*} status_name 
 */
export function get_all_unit_ap_status_count(fight_data, status_name) {
    let staus_count = 0;
    let unit_count = 0;
    fight_data["队伍数据"].forEach((team => {
        team.forEach(unit => {
            if (unit["类型"] === "角色") {
                unit_count++;
                if (unit["法术状态"] && unit["法术状态"][status_name]) {
                    staus_count++;
                }
            }
        });
    }));
    return [staus_count, unit_count];
}

/**
 * 获得友方指定内丹属性数量和参数总和
 * @param {*} fight_data 
 * @param {*} nei_dan_name 
 */
export function get_friend_nei_dan_count(fight_data, fight_unit, nei_dan_name) {
    let count = 0;
    let total = 0;
    fight_data["队伍数据"][fight_unit["队伍下标"]].forEach(unit => {
        if (unit["认证码"] && unit["内丹属性"][nei_dan_name]) {
            count++;
            total += unit["内丹属性"][nei_dan_name];
        }
    });
    return [count, total];
}


/**
 * 添加统计数据
 * @param {*} fight_data 
 * @param {*} fight_unit 
 * @param {*} count_type 
 * @param {*} key 
 */
export function set_fight_count_data(fight_data, fight_unit, count_type, key) {
    if (fight_data["统计数据"][fight_unit["队伍"]] === undefined) {
        fight_data["统计数据"][fight_unit["队伍"]] = {};
    }
    if (fight_data["统计数据"][fight_unit["队伍"]][count_type] === undefined) {
        fight_data["统计数据"][fight_unit["队伍"]][count_type] = {};
    }
    if (fight_data["统计数据"][fight_unit["队伍"]][count_type][key] === undefined) {
        fight_data["统计数据"][fight_unit["队伍"]][count_type][key] = new Set();
    } else {
        fight_data["统计数据"][fight_unit["队伍"]][count_type][key].add(fight_unit["编号"]);
    }
}

/**
 * 统计数据是否存在指定key
 * @param {*} fight_data 
 * @param {*} fight_unit 
 * @param {*} count_type 
 * @param {*} key 
 * @returns 
 */
export function hash_fight_count_data(fight_data, fight_unit, count_type, key) {
    if (fight_data["统计数据"][fight_unit["队伍"]] === undefined || fight_data["统计数据"][fight_unit["队伍"]][count_type] === undefined) {
        return false;
    }
    return fight_data["统计数据"][fight_unit["队伍"]][count_type][key] !== undefined;
}

/**
 * 获取全场指定属性的数量 值是number类型的
 * @param {*} fight_data 
 * @param {*} key 
 * @returns 
 */
export function get_all_number_buff_count(fight_data, key) {
    let count = 0;
    fight_data["队伍数据"].forEach((team => {
        team.forEach(unit => {
            if (unit[key] && unit[key] > 0) {
                count++;
            }
        });
    }));
    return count;
}

/**
 * 取如意神通目标
 * @param {*} fight_data 
 * @param {*} fight_unit 
 */
export function get_ry_skill_target(fight_data, fight_unit) {
    let data = [];
    fight_data["队伍数据"].forEach(team => {
        if (team[0]["队伍"] !== fight_unit["队伍"]) {
            team.forEach(unit => {
                if (G.FightUnitUtils.get_target_unit_status(fight_unit, unit, 1)) {
                    data.push(unit);
                }
            });
        }
    });
    if (data.length === 0) {
        return undefined;
    }
    return G.RandomUtils.random_get_array(data);
}

/**
 * 取多个溅射目标
 * @param {*} fight_data 
 * @param {*} src_unit 
 * @param {*} target_unit 
 * @param {*} num 数量
 */
export function get_jian_she_group(fight_data, src_unit, target_unit, num) {
    let list = [];
    if (G.FightUnitUtils.get_target_unit_status(src_unit, target_unit, 1)) {
        list = [];
    }
    if (src_unit["队伍"] === target_unit["队伍"]) {
        return [];
    }
    if (list >= num) {
        return list;
    }
    for (let index = 0; index < fight_data["队伍数据"].length; index++) {
        let team = fight_data["队伍数据"][index];
        if (team[0]["队伍"] !== src_unit["队伍"]) {
            team.forEach(unit => {
                if (unit["编号"] !== target_unit["编号"] && G.FightUnitUtils.get_target_unit_status(src_unit, unit, 1)) {
                    list.push(unit);
                }
            })
        }
    }
    let result = []
    // 随机顺序取
    for (let index = 0; index < list.length; index++) {
        if (result.length < num) {
            result.push(G.RandomUtils.random_get_array(list));
            list.splice(index, 1);
        }
    }
    return result;
}

export function check_characters_is_fight_unit(characters) {
    if (characters["战斗开关"] === 0) {
        return false;
    }
    let fight_data = _FightDataCache.get(characters["战斗开关"]);
    if (fight_data === undefined) {
        return false;
    }
    let unit_data = get_fight_unit_by_characters(fight_data, characters);
    if (unit_data === undefined) {
        return false;
    }
    return true;
}

export function send_auto_cmd(fight_data, masrster_fight_unit) {
    let is_auto = masrster_fight_unit["自动战斗"];
    let auto_cmd_list = [];
    auto_cmd_list.push({ "id": masrster_fight_unit["编号"], "自动指令": masrster_fight_unit["自动指令"], "自动开关": masrster_fight_unit["自动战斗"] });
    let team_index = masrster_fight_unit["队伍下标"];
    let unit_index = masrster_fight_unit["下标"];
    let team_data = fight_data["队伍数据"][team_index];
    //设置召唤兽自动战斗
    if (masrster_fight_unit["参战宝宝"]) {
        let pet_data = team_data[unit_index + 1];
        pet_data["自动战斗"] = is_auto;
        auto_cmd_list.push({ "id": pet_data["编号"], "自动指令": pet_data["自动指令"], "自动开关": pet_data["自动战斗"] });
    }
    //设置助战自动战斗
    for (let index = 0; index < team_data.length; index++) {
        let fight_unit = team_data[index];
        if (fight_unit["类型"] === "角色") {
            let help_characters = _CharactersData.get(fight_unit["id"]);
            let character_client_id = G.Characters.get_characters_client_id(fight_unit["id"]);
            if (character_client_id === undefined) {
                //没有客户端id要么离线要么是助战角色
                let master_id = G.Characters.get_master_characters_id(fight_unit["id"]);
                if (master_id === masrster_fight_unit["id"]) {
                    // 当前主角色的助战
                    fight_unit["自动战斗"] = is_auto;
                    help_characters["自动战斗"] = is_auto;
                    auto_cmd_list.push({ "id": fight_unit["编号"], "自动指令": fight_unit["自动指令"], "自动开关": fight_unit["自动战斗"] });
                }
            }
        }
    }
    // 通知客户端更新指定单位的自动指令内容和自动状态
    ClientUtils.send_characters_client_message(masrster_fight_unit["id"], 5513, auto_cmd_list);
}

/**
 * 更新自动战斗
 * @param {*} characters 
 */
export function update_auto_cmd(characters) {
    let fight_data = _FightDataCache.get(characters["战斗开关"]);
    if (fight_data) {
        let masrster_fight_unit = get_fight_unit_by_characters(fight_data, characters);
        let is_auto = !masrster_fight_unit["自动战斗"];
        //设置主角色自动战斗
        characters["自动战斗"] = is_auto;
        masrster_fight_unit["自动战斗"] = is_auto;
        // 如果当前处于等待指令阶段并且客户端还没有提交命令则模拟提交一次命令
        if (is_auto && fight_data["战斗状态"] === "等待指令" && characters["历史指令"]) {
            set_cmd(characters, characters["历史指令"]);
        }
        let text = is_auto ? "开启" : "取消";
        ClientUtils.send_characters_basic_prompt(characters["id"], `#Y/你${text}了自动战斗`);
        send_auto_cmd(fight_data, masrster_fight_unit)
    }
}

/**
 * 添加战斗提示
 * @param {*} fight_data 
 * @param {*} src_unit 
 * @param {*} target_unit 
 * @param {*} text 
 */
export function add_fight_prompt(fight_data, src_unit, target_unit, text) {
    fight_data["战斗流程"].push({ "流程": 901, "攻击方": src_unit["编号"], "id": target_unit["id"], "内容": text });
}

/**
 * 查找友方队伍有多少种宠物
 * @param {*} fight_data 
 * @param {*} fight_unit 
 * @returns 
 */
export function get_friend_team_pet_model_count(fight_data, fight_unit) {
    let list = new Set();
    let team_data = fight_data["队伍数据"][fight_unit["队伍下标"]];
    team_data.forEach(unit => {
        if (unit["类型"] === "bb") {
            list.add(unit["模型"])
        }
    });
    return list.size;
}